
#pragma once

#include <type_traits>

namespace atr {
namespace core {

/** Partial specialization for metaprograming bool type */
template <bool Boolean>
using _bool  = std::integral_constant<bool, Boolean>;

/** Predefined true type */
using _true  = _bool<true>;

/** Predefined false type */
using _false = _bool<false>;

/**
 * @brief   Metaprograming not operator
 * @details Implements operation not in metaprogramint style
 *
 * @tparam  class Boolean parameter to negate
 *
 * @todo    Add ability to provide more than one argument
 */
template <typename Boolean>             struct _not
{
    /** Result type for default operation not */
    using type = _false;
};

/**
 * @brief   Metaprograming not operator - specialization
 * @details Implements operation not in metaprogramint style.
 *          This is specialization for false type.
 *
 * @todo    Add ability to provide more than one argument
 */
template <>
struct _not<_false>
{
    /** Result type for specialized operation not */
    using type = _true;
};

/**
 * @brief   Operator or on atr::boolean types
 * @details Operator implements simply or operation on boolean types. It can be
 *          used with more than one type and it provides short determining.
 *
 * @tparam  class ... Boolean sequence of values to evaluate
 */
template <typename ... Boolean>         struct _or
{
    /** Result type for default operator or */
    using type = _false;
};

/**
 * @brief   Operator or on atr::boolean types - terminator
 * @details Operator implements simply or operation on boolean types. It can be
 *          used with more than one type and it provides short determining. This
 *          partial specialization implements terminator, when we know already
 *          that all expression is true
 *
 * @tparam  class ... Boolean sequence of values to evaluate
 */
template <typename ... Boolean>
struct _or<_true, Boolean...>
{
    /** Result type for specialized operator or */
    using type = _true;
};

/**
 * @brief   Operator or on atr::boolean types - recurence
 * @details Operator implements simply or operation on boolean types. It can be
 *          used with more than one type and it provides short determining. This
 *          implementation provides checking next types
 *
 * @tparam  class ... Boolean sequence of values to evaluate
 */
template <typename ... Boolean>
struct _or<_false, Boolean...>
    : public _or<Boolean...> {};

/**
 * @brief   Operator and on atr::boolean types
 * @details Operator implements simply and operation on boolean types. It can be
 *          used with more than one type and it provides short determining.
 *
 * @tparam  class ... Boolean sequence of values to evaluate
 */
template <typename ... Boolean>         struct _and
{
    /** Result type for default operator and */
    using type = _true;
};

/**
 * @brief   Operator or and atr::boolean types - terminator
 * @details Operator implements simply and operation on boolean types. It can be
 *          used with more than one type and it provides short determining. This
 *          partial specialization implements terminator, when we know already
 *          that all expression is false
 *
 * @tparam  class ... Boolean sequence of values to evaluate
 */
template <typename ... Boolean>
struct _and<_false, Boolean...>
{
    /** Result type for specialized operator and */
    using type = _false;
};

/**
 * @brief   Operator and on atr::boolean types - recurence
 * @details Operator implements simply and operation on boolean types. It can be
 *          used with more than one type and it provides short determining. This
 *          implementation provides checking next types
 *
 * @tparam  class ... Boolean sequence of values to evaluate
 */
template <typename ... Boolean>
struct _and<_true, Boolean...>
    : public _and<Boolean...> {};

/**
 * @brief   Operator xor on atr::boolean types
 * @details Operator xor.
 *
 * @tparam  class Boolean1 first boolean type
 * @tparam  class Boolean2 second boolean type
 *
 * @todo    Provide functionality to use more than two types
 */
template <typename Boolean1,
          typename Boolean2>            struct _xor
{
    /** Result type for operator xor */
    using type = _true;
};

/**
 * @brief   Operator xor on atr::boolean types
 * @details Operator xor. Specialization when both types are same.
 *
 * @tparam  class Boolean first boolean type
 *
 * @todo    Provide functionality to use more than two types
 */
template <typename Boolean>
struct _xor<Boolean, Boolean>
{
    /** Result type for operator xor */
    using type = _false;
};

} // namespace core
} // namespace atr

